// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PersistedFileRequest.cs" company="XamlNinja">
//   2011 Richard Griffin and Ollie Riches
// </copyright>
// <summary>
//   PersistedFileRequest.cs
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace WP7Contrib.Services.DownloadManager
{
    using System;
    using Common;
    using global::Serialization;

    /// <summary>
    /// Persistable version of the class FileRequest - we persist the file download requests to persistent storage.
    /// We only persist the url, file & the current state.
    /// </summary>
    internal sealed class PersistedFileRequest : BaseModel, IFileRequestPropertyChanged, IEquatable<PersistedFileRequest>
    {
        public PersistedFileRequest()
        {
            this.Identifier = Guid.NewGuid();
            this.CreatedOn = DateTime.Now;
            this.State = FileRequestState.NotStarted;
        }

        private Guid identifier;
        private DateTime createdOn;
        private string urlAsString;
        private string filePath;
        private FileRequestState state;
        private TimeSpan duration;
        private long contentLength;
        private long fileLength;
        private bool resumable;
        private int blockSize;
        private Exception exception;

        /// <summary>
        /// Unique identfier for request.
        /// </summary>
        public Guid Identifier
        {
            get
            {
                return this.identifier;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.identifier, value, () => Identifier);
            }
        }

        /// <summary>
        /// The date the request was created on.
        /// </summary>
        public DateTime CreatedOn
        {
            get
            {
                return this.createdOn;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.createdOn, value, () => CreatedOn);
            }
        }

        /// <summary>
        /// The url of the file being downloaded as a string.
        /// </summary>
        public string UrlAsString
        {
            get
            {
                return this.urlAsString;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.urlAsString, value, () => UrlAsString);
                this.Url = !string.IsNullOrEmpty(this.urlAsString) ? new Uri(this.urlAsString) : null;
            }
        }

        /// <summary>
        /// The url of the file being downloaded generated from the 'url as string' property
        /// </summary>
        [DoNotSerialize]
        public Uri Url { get; private set; }

        /// <summary>
        /// The local file path, this is where the file when downloaded will be copied too.
        /// </summary>
        public string FilePath
        {
            get
            {
                return this.filePath;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.filePath, value, () => FilePath);
            }
        }

        /// <summary>
        /// The current state of this request.
        /// </summary>
        public FileRequestState State
        {
            get
            {
                return this.state;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.state, value, () => State);
            }
        }

        /// <summary>
        /// The total time to download the current file length.
        /// </summary>
        public TimeSpan Duration
        {
            get
            {
                return this.duration;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.duration, value, () => Duration);
            }
        }

        /// <summary>
        /// The content length of the file at the Url.
        /// </summary>
        [DoNotSerialize]
        public long ContentLength
        {
            get
            {
                return this.contentLength;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.contentLength, value, () => ContentLength);
            }
        }

        /// <summary>
        /// The local file length.
        /// </summary>
        [DoNotSerialize]
        public long FileLength
        {
            get
            {
                return this.fileLength;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.fileLength, value, () => FileLength);
            }
        }
        
        /// <summary>
        /// Defines if this file request is a resumable download.
        /// </summary>
        [DoNotSerialize]
        public bool Resumable
        {
            get
            {
                return this.resumable;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.resumable, value, () => Resumable);
            }
        }

        /// <summary>
        /// The block size used for resumable downloads.
        /// </summary>
        [DoNotSerialize]
        public int BlockSize
        {
            get
            {
                return this.blockSize;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.blockSize, value, () => BlockSize);
            }
        }


        /// <summary>
        /// The current exception of this request.
        /// </summary>
        public Exception Exception
        {
            get
            {
                return this.exception;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.exception, value, () => Exception);
            }
        }
        
        public static bool operator ==(PersistedFileRequest pfr1, PersistedFileRequest pfr2)
        {
            return Equals(pfr1, pfr2);
        }

        public static bool operator !=(PersistedFileRequest pfr1, PersistedFileRequest pfr2)
        {
            return !Equals(pfr1, pfr2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is PersistedFileRequest && this.Equals((PersistedFileRequest) obj);
        }

        public override int GetHashCode()
        {
            return this.CombineHashCodes(this.Identifier, this.CreatedOn, this.UrlAsString, this.FilePath, this.State, this.Duration);
        }

        public bool Equals(PersistedFileRequest request)
        {
            if (ReferenceEquals(null, request))
            {
                return false;
            }

            if (this.Identifier != request.Identifier)
            {
                return false;
            }

            if (this.CreatedOn != request.CreatedOn)
            {
                return false;
            }

            if (this.UrlAsString != request.UrlAsString)
            {
                return false;
            }

            if (this.FilePath != request.FilePath)
            {
                return false;
            }

            if (this.State != request.State)
            {
                return false;
            }

            if (this.Duration != request.Duration)
            {
                return false;
            }

            return true;
        }
    }
}